﻿/// <reference path="~/Scripts/jquery-1.4.1-vsdoc.js" />

(function ($) {
    $.fn.gridify = function (options) {
        options = $.extend(options, {});

        var behaviours = this.behaviours = {};

        this.behaviours["paging"] = function (meta, reloadCallback) {
            $.extend(meta.data, {
                currentPage: 0,
                totalPages: options.totalPages
            });

            var titleText = "({0}/{1})";
            var headerPanel = $("<div class='gridify-header' />");
            var footerPanel = $("<div class='gridify-footer' />");
            var backLink = $("<a class='gridify-prev' href='" + meta.url + "' />").text("previous");
            var bottomBackLink = backLink.clone();
            var forwardLink = $("<a class='gridify-next' href='" + meta.url + "'/>").text("next");
            var bottomForwardLink = forwardLink.clone();
            var title = $("<span class='gridify-title'>" + titleText + "</span>");

            $(".gridify-next").live("click", function () {
                return reloadCallback(1);
            });

            $(".gridify-prev").live("click", function () {
                return reloadCallback(-1);
            });

            var invalidateLinks = function () {
                if (meta.data.currentPage > 0)
                    $(".gridify-prev").show();
                else
                    $(".gridify-prev").hide();

                if (meta.data.currentPage >= parseInt(meta.data.totalPages))
                    $(".gridify-next").hide();
                else
                    $(".gridify-next").show();
            };

            var invalidateTitle = function () {
                title.text(titleText.replace("{0}", meta.data.currentPage + 1).replace("{1}", parseInt(meta.data.totalPages) + 1));
            }

            var invalidatePanels = function () {
                headerPanel.append(backLink).append(title).append(forwardLink);
                footerPanel.append(bottomBackLink).append(bottomForwardLink);

                headerPanel.width(meta.table.outerWidth()).css("margin-left", meta.table.css("margin-left")).css("margin-right", meta.table.css("margin-right"));
                footerPanel.width(meta.table.outerWidth()).css("margin-left", meta.table.css("margin-left")).css("margin-right", meta.table.css("margin-right"));

                meta.table.before(headerPanel);
                meta.table.after(footerPanel);
            }

            this.startLoading = function () {
                $(".gridify-prev").hide();
                $(".gridify-next").hide();
            }

            this.endLoading = function (result) {
                invalidatePanels();
                invalidateTitle();
                invalidateLinks();
            }

            invalidatePanels();
            invalidateTitle();
            invalidateLinks();
        }

        this.behaviours["filtering"] = function (meta, reloadCallback) {
            $.extend(meta.data, {
                filters: []
            });
            var inputs = {};
            var inputContainer = $("<div class='gridify-filter'><input type='text'></input></div>");

            var setFilterValue = function (columnName, value) {
                for (var i in meta.data.filters) {
                    if (meta.data.filters[i].column == columnName) {
                        meta.data.filters[i].value = value;
                        break;
                    }
                }
            }

            var invalidateFilters = function () {
                meta.dataColumns.each(function (i, e) {
                    var je = $(e);
                    var columnName = je.attr('data-column-name');
                    if (!inputs[columnName]) {
                        meta.data.filters.push({ column: je.attr('data-column-name'), value: '' });
                        var position = je.offset();
                        var input = inputContainer.clone().appendTo("body");
                        input.offset({ top: position.top - input.outerHeight(), left: position.left })
                         .width(je.outerWidth()).hide()
                         .find("input").width(je.width()).blur(function () {
                             if ($(this).val().length == 0) {
                                 input.fadeOut('fast');
                             }
                         }).keyup(function () {
                             setFilterValue(je.attr('data-column-name'), $(this).val());
                             reloadCallback(0);
                         });
                        je.mouseenter(function () {
                            input.fadeIn('fast');
                        });
                        inputs[columnName] = input;
                    } else {
                        var input = inputs[columnName];
                        var position = je.offset();
                        input.offset({ top: position.top - input.outerHeight(), left: position.left });
                        je.mouseenter(function () {
                            input.fadeIn('fast');
                        });
                    }
                });
            }

            this.endLoading = function (result) {
                invalidateFilters();
            }

            invalidateFilters();
        }

        this.behaviours["sorting"] = function (meta, reloadCallback) {
            $.extend(meta.data, {
                sortBy: {}
            });

            $(".gridify-sort").live("click", function () {
                var column = $(this).closest("th, td").attr("data-column-name");
                if (!!meta.data.sortBy.column && column == meta.data.sortBy.column) {
                    meta.data.sortBy.dir = !meta.data.sortBy.dir;
                    reloadCallback(0);
                    return;
                }

                if (!!meta.data.sortBy.elem)
                    meta.data.sortBy.elem.remove();

                meta.data.sortBy.column = column;
                meta.data.sortBy.dir = true;

                reloadCallback(0);
            });

            var invalidateSortings = function () {
                meta.dataColumns.each(function (i, e) {
                    $(this).html("<span class='gridify-sort'>" + $(this).html() + "</span>");
                    if (meta.data.sortBy.column && meta.data.sortBy.column == $(this).attr("data-column-name")) {
                        meta.data.elem = $("<span class='gridify-sort-" + (meta.data.sortBy.dir ? "up" : "down") + "' />");
                        $(this).append(meta.data.elem);
                    }
                });
            }

            this.endLoading = function (result) {
                invalidateSortings();
            }

            invalidateSortings();
        }

        return this.each(function () {
            var $this = $(this);
            var meta = {
                table: $this,
                dataColumns: $("[data-column-name]", $this),
                data: {},
                totalPages: options.TotalPages,
                url: options.pageLink
            }

            var startLoading = function () {
                $this.fadeOut();
                for (var b in behaviours)
                    if (!!behaviours[b].startLoading)
                        behaviours[b].startLoading()
            }

            var endLoading = function (result) {
                if (!!result.failure)
                    window.location = window.location;

                $this.fadeIn();

                var newThis = $(result);
                $this = $this.replaceWith(newThis);
                $this = newThis;

                meta.dataColumns = $("[data-column-name]", $this);
                meta.table = $this;

                for (var b in behaviours)
                    if (!!behaviours[b].endLoading)
                        behaviours[b].endLoading();
            }

            var getFiltersObject = function (filters) {
                var result = {};
                for (var i = 0; i < filters.length; i++) {
                    var filter = filters[i];
                    result['filters[' + i + '].column'] = filter.column;
                    result['filters[' + i + '].value'] = filter.value;
                }
                return result;
            }

            var reload = function (pageOffset) {
                startLoading();
                $.get(options.pageLink,
                    $.extend(getFiltersObject(meta.data.filters), {
                        page: meta.data.currentPage + pageOffset,
                        id: options.gridId,
                        sortBy: meta.data.sortBy.column,
                        sortDir: meta.data.sortBy.dir ? 1 : 0
                    }), function (result, status, request) {
                        meta.data.currentPage = pageOffset + meta.data.currentPage;
                        meta.data.totalPages = parseInt(request.getResponseHeader("TotalPages"));

                        if (meta.data.currentPage > meta.data.totalPages) {
                            meta.data.currentPage = meta.data.totalPages;
                            reload(pageOffset, result);
                        }
                        endLoading(result);
                    });
                return false;
            }

            for (var b in behaviours)
                behaviours[b].call(behaviours[b], meta, reload);
        });
    }
})(jQuery);